using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace SilverSea.Video.Tools
{
	public class AVIWriter : IDisposable
	{
		private IntPtr intptr_0;
		private IntPtr intptr_1;
		private IntPtr intptr_2;
		private IntPtr intptr_3 = IntPtr.Zero;
		private int int_0;
		private int int_1;
		private int int_2;
		private int int_3 = -1;
		private int int_4 = 25;
		private int int_5;
		private string string_0 = "DIB ";
		private object object_0 = new object();
		public int Width
		{
			get
			{
				if (!(this.intptr_3 != IntPtr.Zero))
				{
					return 0;
				}
				return this.int_0;
			}
		}
		public int Height
		{
			get
			{
				if (!(this.intptr_3 != IntPtr.Zero))
				{
					return 0;
				}
				return this.int_1;
			}
		}
		public int Position
		{
			get
			{
				return this.int_5;
			}
		}
		public int FrameRate
		{
			get
			{
				return this.int_4;
			}
			set
			{
				this.int_4 = value;
			}
		}
		public string Codec
		{
			get
			{
				return this.string_0;
			}
			set
			{
				this.string_0 = value;
			}
		}
		public int Quality
		{
			get
			{
				return this.int_3;
			}
			set
			{
				this.int_3 = value;
			}
		}
		public AVIWriter()
		{
			Win32.AVIFileInit();
		}
		public AVIWriter(string codec, int rate) : this()
		{
			this.string_0 = codec;
			this.int_4 = rate;
		}
		~AVIWriter()
		{
			this.Dispose(false);
		}
		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}
		protected virtual void Dispose(bool disposing)
		{
			this.Close();
			Win32.AVIFileExit();
		}
		public void Open(string fileName, int width, int height)
		{
			this.Close();
			lock (this.object_0)
			{
				this.int_2 = width * 3;
				if (this.int_2 % 4 != 0)
				{
					this.int_2 += 4 - this.int_2 % 4;
				}
				if (Win32.AVIFileOpen(out this.intptr_0, fileName, (Win32.OpenFileMode)4097, IntPtr.Zero) != 0)
				{
					throw new ApplicationException("Failed opening file");
				}
				this.int_0 = width;
				this.int_1 = height;
				Win32.AVISTREAMINFO aVISTREAMINFO = default(Win32.AVISTREAMINFO);
				aVISTREAMINFO.type = Win32.mmioFOURCC("vids");
				aVISTREAMINFO.handler = Win32.mmioFOURCC(this.string_0);
				aVISTREAMINFO.scale = 1;
				aVISTREAMINFO.rate = this.int_4;
				aVISTREAMINFO.suggestedBufferSize = this.int_2 * height;
				if (Win32.AVIFileCreateStream(this.intptr_0, out this.intptr_1, ref aVISTREAMINFO) != 0)
				{
					throw new ApplicationException("Failed creating stream");
				}
				Win32.AVICOMPRESSOPTIONS aVICOMPRESSOPTIONS = default(Win32.AVICOMPRESSOPTIONS);
				aVICOMPRESSOPTIONS.handler = Win32.mmioFOURCC(this.string_0);
				aVICOMPRESSOPTIONS.quality = this.int_3;
				if (Win32.AVIMakeCompressedStream(out this.intptr_2, this.intptr_1, ref aVICOMPRESSOPTIONS, IntPtr.Zero) != 0)
				{
					throw new ApplicationException("Failed creating compressed stream");
				}
				Win32.BITMAPINFOHEADER bITMAPINFOHEADER = default(Win32.BITMAPINFOHEADER);
				bITMAPINFOHEADER.size = Marshal.SizeOf(bITMAPINFOHEADER.GetType());
				bITMAPINFOHEADER.width = width;
				bITMAPINFOHEADER.height = height;
				bITMAPINFOHEADER.planes = 1;
				bITMAPINFOHEADER.bitCount = 24;
				bITMAPINFOHEADER.sizeImage = 0;
				bITMAPINFOHEADER.compression = 0;
				if (Win32.AVIStreamSetFormat(this.intptr_2, 0, ref bITMAPINFOHEADER, Marshal.SizeOf(bITMAPINFOHEADER.GetType())) != 0)
				{
					throw new ApplicationException("Failed creating compressed stream");
				}
				this.intptr_3 = Marshal.AllocHGlobal(this.int_2 * height);
				if (this.intptr_3 == IntPtr.Zero)
				{
					throw new ApplicationException("Insufficient memory for internal buffer");
				}
				this.int_5 = 0;
			}
		}
		public void Close()
		{
			lock (this.object_0)
			{
				if (this.intptr_3 != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(this.intptr_3);
					this.intptr_3 = IntPtr.Zero;
				}
				if (this.intptr_2 != IntPtr.Zero)
				{
					Win32.AVIStreamRelease(this.intptr_2);
					this.intptr_2 = IntPtr.Zero;
				}
				if (this.intptr_1 != IntPtr.Zero)
				{
					Win32.AVIStreamRelease(this.intptr_1);
					this.intptr_1 = IntPtr.Zero;
				}
				if (this.intptr_0 != IntPtr.Zero)
				{
					Win32.AVIFileRelease(this.intptr_0);
					this.intptr_0 = IntPtr.Zero;
				}
			}
		}
		public void AddFrame(System.Drawing.Bitmap frameImage)
		{
			lock (this.object_0)
			{
				if (this.intptr_3 == IntPtr.Zero)
				{
					throw new ApplicationException("AVI file should be successfully opened before writing");
				}
				if (frameImage.Width == this.int_0)
				{
					if (frameImage.Height == this.int_1)
					{
						System.Drawing.Imaging.BitmapData bitmapData = frameImage.LockBits(new System.Drawing.Rectangle(0, 0, this.int_0, this.int_1), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
						int stride = bitmapData.Stride;
						int num = this.int_2;
						int num2 = bitmapData.Scan0.ToInt32() + stride * (this.int_1 - 1);
						int num3 = this.intptr_3.ToInt32();
						for (int i = 0; i < this.int_1; i++)
						{
							Win32.memcpy(num3, num2, num);
							num3 += num;
							num2 -= stride;
						}
						frameImage.UnlockBits(bitmapData);
						if (Win32.AVIStreamWrite(this.intptr_2, this.int_5, 1, this.intptr_3, this.int_2 * this.int_1, 0, IntPtr.Zero, IntPtr.Zero) != 0)
						{
							throw new ApplicationException("Failed adding frame");
						}
						this.int_5++;
						return;
					}
				}
				throw new ApplicationException("Invalid image dimension");
			}
		}
	}
}
